package com.jindi.jacococli.biz.business.service;

import com.jindi.jacococli.biz.business.queue.JacocoCliEvent;
import org.jacoco.core.data.ExecutionDataWriter;
import org.jacoco.core.data.IncompatibleExecDataVersionException;
import org.jacoco.core.runtime.RemoteControlReader;
import org.jacoco.core.runtime.RemoteControlWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.util.List;
import java.util.Objects;

import static com.jindi.jacococli.biz.constant.Constant.JACOCO_EXEC;

/**
 * 从服务端拉取 jacocoCli的统计数据
 *  1.找到一个可以获取jacoco服务端数据的节点就可以
 */
@Service
public class JacocoCliService {

    public static final Logger LOGGER = LoggerFactory.getLogger(JacocoCliService.class);
    public boolean fetchExecFile(JacocoCliEvent cliEvent) {
        boolean result = false;
        List<JacocoCliEvent.Node> nodes = cliEvent.getNodes();
        Socket socket = null;
        for (JacocoCliEvent.Node node : nodes) {
            socket = createSocket(node);
            if (Objects.nonNull(socket)) {
                break;
            }
        }
        if (Objects.isNull(socket)) {
            LOGGER.info("jacoco service:{}, has no socket", cliEvent.getServiceName());
            return false;
        }
        File localDir = new File(cliEvent.getWorkSpace());
        if (!localDir.exists()) {
            localDir.mkdirs();
        }
        try (FileOutputStream localFile = new FileOutputStream(cliEvent.getWorkSpace() + cliEvent.getServiceName() + JACOCO_EXEC)) {
            final ExecutionDataWriter localWriter = new ExecutionDataWriter(localFile);
            // Open a socket to the coverage agent:
            final RemoteControlWriter writer = new RemoteControlWriter(socket.getOutputStream());
            final RemoteControlReader reader = new RemoteControlReader(socket.getInputStream());
            reader.setSessionInfoVisitor(localWriter);
            reader.setExecutionDataVisitor(localWriter);
            // Send a dump command and read the response:
            writer.visitDumpCommand(true, false);
           if (reader.read()) {
               result = true;
           }
        } catch (FileNotFoundException e) {
           LOGGER.warn("jacoco localFile NotFound", e);
        } catch (IncompatibleExecDataVersionException e) {
            LOGGER.warn("jacoco IncompatibleExecDataVersionException", e);
        } catch (Exception e) {
            LOGGER.warn("jacoco io Exception", e);
        }
        closeSocket(socket);
        return result;
    }
    private Socket createSocket(JacocoCliEvent.Node node) {
        try {
            return new Socket(InetAddress.getByName(node.getIp()), node.getPort());
        } catch (Exception e) {
            LOGGER.warn("jacoco server port no open! node: {}", node.toString());
        }
        return null;
    }

    private void closeSocket(Socket socket) {
        if (socket != null) {
            try {
                socket.close();
            } catch (IOException e) {
                LOGGER.warn("jacoco server socket close error socket: {}", socket.getInetAddress());
            }
        }
    }

}
